package cn.wolfcode.config;

import cn.wolfcode.realm.CrmRealm;
import com.jagregory.shiro.freemarker.ShiroTags;
import freemarker.template.TemplateException;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author jishushen
 * @create 2021-02-18 13:43
 * 之前在ssm中的shiro配置全部转移到了JavaBean中进行配置
 * 此类就是shiro的配置类
 */
@Configuration
public class ShiroConfig {

    @Autowired
    private DefaultWebSecurityManager securityManager;

    //配置过滤器
    //配置ShiroFilterFactoryBean :3
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean() {
        //1.创建过滤器的工厂
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //2.设置安全管理器
        bean.setSecurityManager(securityManager);
        //3.通用配置（跳转登录页面，未授权跳转的页面）
        bean.setLoginUrl("/login.html"); //未认证时，跳转的url
        bean.setUnauthorizedUrl("/error/unauthorized.do"); //未授权时跳转的url

        //4.设置过滤器集合
        Map<String, String> filterMap = new LinkedHashMap<>();
        //anon -- 放行
        filterMap.put("/login/login.do", "anon");
        filterMap.put("/css/**", "anon");
        filterMap.put("/js/**", "anon");
        filterMap.put("/login.html", "anon");
        filterMap.put("/favicon.ico", "anon");

        // 针对Swagger2拦截放行
        filterMap.put("/swagger-ui.html", "anon");
        filterMap.put("/swagger/**", "anon");
        filterMap.put("/swagger-resources/**", "anon");
        filterMap.put("/v2/**", "anon");
        filterMap.put("/webjars/**", "anon");
        filterMap.put("/configuration/**", "anon");

        //logout -- 退出
        filterMap.put("/login/logout.do", "logout");

        //authc -- 认证之后访问（登录）
        filterMap.put("/**", "authc");//拦截所有
        //perms -- 具有某中权限 (使用注解配置授权)
        bean.setFilterChainDefinitionMap(filterMap);

        return bean;
    }

    //配置安全管理器
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("crmRealm") CrmRealm crmRealm, @Qualifier("sessionManager") DefaultWebSessionManager sessionManager) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(crmRealm);
        // 注入session的管理
        securityManager.setSessionManager(sessionManager);
        return securityManager;
    }


    @Bean
    public DefaultWebSessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        // 去掉shiro登录时url里的JSESSIONID
        /**
         * 因为我们的shiro拦截所有，所有我们当访问: http://localhost:8080 的时候他应该跳转到登录页面
         * 也就是： http://localhost:8080/login.html 这是正确的，但是呢？我们这里会出现一个新的东西
         * 那就是jsessionid，所有他真整的访问路径就变为：
         * http://localhost:8080/login.html;jsessionid=F16E104CBC79E73C60CF2DF366BACB73
         * 当成为这个路径之后就会报错：”There was an unexpected error (type=Bad Request, status=400).“
         * 所以我们应该去除掉这个jsessionid,所以才配置了这个Bean
         * DefaultWebSessionManager,并且把这个bean加入到securityManager中
         */
        sessionManager.setSessionIdUrlRewritingEnabled(false);
        return sessionManager;
    }

    //开启对shiro注解的支持
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

    //加密
    //指定当前需要使用的凭证匹配器
    @Bean
    public CredentialsMatcher credentialsMatcher() {
        return new HashedCredentialsMatcher("MD5");
    }

    //把 realm加入到spring容器中
    @Bean
    public CrmRealm crmRealm() {
        return new CrmRealm();
    }

    //freemarker整合shiro标签
    @Bean
    public FreeMarkerConfigurer freeMarkerConfigurer() throws IOException, TemplateException {
        FreeMarkerConfigurer freeMarkerConfigurer = new FreeMarkerConfigurer();
        freeMarkerConfigurer.setTemplateLoaderPath("classpath:templates/views");
        freemarker.template.Configuration configuration = freeMarkerConfigurer.createConfiguration();
        configuration.setDefaultEncoding("UTF-8");
        //这里可以添加其他共享变量 比如sso登录地址
        configuration.setSharedVariable("shiro", new ShiroTags());
        freeMarkerConfigurer.setConfiguration(configuration);
        return freeMarkerConfigurer;
    }
}
